export {}
// 1.内置条件类型
namespace a {
    // 8.1Exclude 从 T 可分配给的类型中排除 U
    type Exclude<T,U> = T extends U ? never : T
    type E = Exclude<string|number,string>; //type E = number

    // 8.2 Extract 从 T 可分配的类型中提取 U
    type Extract<T,U> = T extends U ? T : never
    type  F = Extract<string|number,string>; //type F = string

    // 8.3 NonNullable 从 T 中排除 null 和 undefined
    type NonNullable<T> = T extends null|undefined ? never : T
    type  NullAndUndefined = NonNullable<string|number|null|undefined>; //type NullAndUndefined = string | number

    // 8.4 ReturnType 重点
    // infer最早出现在此 PR 中，表示在 extends 条件语句中待推断的类型变量
    // 获取函数类型的返回类型
    type ReturnType <T extends ((...args:any[])=>any)> = T extends (...args:any[])=>infer R ? R  : never
    function getUserInfo() {
        return { name: "ikki", age: 10 };
    }
    // 通过 ReturnType 将 getUserInfo 的返回值类型赋给了 UserInfo
    type UserInfo = ReturnType<typeof getUserInfo>;
    const userA: UserInfo = {
        name: "ikki",
        age: 10
    };

    // 8.5 Parameters 获取函数的参数
    type Parameters<T> = T extends (...args: infer P)=>any ? P : never
    type T0 = Parameters<() => string>;  // []
    type T1 = Parameters<(s: string,b:number) => void>;  // [s: string, b: number]
    type T2 = Parameters<(<T>(arg: T) => T)>;  // [unknown]

    // 8.6 InstanceType 获取构造函数类型的实例类型
    type Constructor = new (...args: any[]) => any; 
    type InstanceType<T extends Constructor> = T extends new (...args: any[]) => infer R ? R : any;
    class Person {
        name: string;
        constructor(name: string) {
            this.name = name;
        }
        getName() { console.log(this.name) }
    }

    //实例类型
    type Instance = InstanceType<typeof Person>;
    let instance: Instance = { name: 'ikki', getName() { } };

    // constructorParameters 获取构造函数的参数
    type ConstructorParameters<T extends Constructor> = T extends new (...args: infer P) => any ? P : never;
    class Person4 {
        name: string;
        constructor(name: string) {
            this.name = name;
        }
        getName() { console.log(this.name) }
    }
    type constructorParameters = ConstructorParameters<typeof Person4>;
    let params: constructorParameters = ['ikki']

    // 8.7 infer实用案例
    // tuple转union
    type ElementOf<T> = T extends Array<infer E> ? E : never
    type TTuple = [string, number];
    type ToUnion = ElementOf<TTuple>; // string | number
    // 联合类型（Union Types）表示取值可以为多种类型中的一种
    //交叉类型（Intersection Types）表示将多个类型合并为一个类型
    // union 转 intersection
    type UnionToIntersection<T> = T extends { a: (x: infer U) => void; b: (x: infer U) => void } ? U : never
    type T11 = { name: string };
    type T2222 = { age: number };
    type T33 = UnionToIntersection<{ a: (x: T11) => void; b: (x: T2222) => void }>; // T1 & T2
}

// 2.内置工具类型
namespace j {
    // 2.1Partial 可以将传入的属性由非可选变为可选
    type Partial<T> = {[ P in keyof T]?: T[P]}
    interface A {
        a1: string;
        a2: number;
        a3: boolean;
      }
    type aPartial = Partial<A>;
    const a: aPartial = {};

    // 2.2 类型递归
    type DeepPartial<T> = {
        [ P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]
    }
    interface Company {
        id: number
        name: string
    }
    interface Person {
        id: number
        name: string
        company: Company
    }
    type R2 = DeepPartial<Person>

    // 2.3 Required 可以将传入的属性中的可选项变为必选项，这里用了 -? 修饰符来实现
    interface Person2{
        name:string;
        age:number;
        gender?:'male'|'female';
    }
    type Require<T> = { [P in keyof T]-?: T[P] };
    let kk:Required<Person2> = {
        name:'ikki',
        age:10,
        gender:'male'
    }

    // 2.4 Readonly 为传入的属性每一项都加上 readonly 修饰符来实现。
    type Readonly<T> = { readonly [P in keyof T]: T[P] };
    let p:Readonly<Person2> = {
        name:'ikki',
        age:10,
        gender:'male'
    }

    // 2.5 Pick 能够帮助我们从传入的属性中摘取某一项返回
    type Pick<T, K extends keyof T> = {
        [P in K] : T[P]
    }
    interface Person3 {
        name: string;
        age: number;
        married: boolean
    }
    let person: Person3 = { name: 'ikki', age: 10, married: true };
    let result: Pick<Person3, 'name' | 'age'>  = { name:'ikki',age:20 }

    // 2.6 Record 将一个类型的所有属性值都映射到另一个类型上并创造一个新的类型
    type Record<K extends keyof any, T> = {
        [P in K]: T;
    };
    function mapObject<K extends string | number, T, U>(obj: Record<K, T>, map: (x: T) => U): Record<K, U> {
        let result: any = {};
        for (const key in obj) {
            result[key] = map(obj[key]);
        }
        return result;
    }
    let names = { 0: 'hello', 1: 'world' };
    let lengths = mapObject<string | number, string, number>(names, (s: string) => s.length);
    console.log(lengths);//{ '0': 5, '1': 5 }


    //any的 keyof
    type keyofAny = keyof any  //type keyofAny = string | number | symbol

}

